package com.ocean.pokesync.hook;

import com.ocean.PokeSyncReforged;
import com.ocean.pokesync.data.Config;
import com.ocean.pokesync.data.PixelmonDataType;
import com.ocean.pokesync.hook.PokeSyncMixinsHook;
import com.ocean.pokesync.utils.LogUtils;
import com.ocean.pokesync.utils.PixelUtils;
import com.pixelmonmod.pixelmon.api.storage.PCStorage;
import com.pixelmonmod.pixelmon.api.storage.PlayerPartyStorage;
import com.pixelmonmod.pixelmon.api.storage.StorageProxy;
import net.minecraft.core.HolderLookup;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.server.ServerLifecycleHooks;
import net.william278.husksync.HuskSync;
import net.william278.husksync.api.HuskSyncAPI;
import net.william278.husksync.event.BukkitDataSaveEvent;
import net.william278.husksync.event.BukkitPreSyncEvent;
import net.william278.husksync.event.BukkitSyncCompleteEvent;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;

import java.util.UUID;


public class HuskSyncAPIHook implements Listener {

    private final HuskSyncAPI huskSyncAPI;
    private final boolean usePokeSyncMixins;

    public HuskSyncAPIHook() {
        this.huskSyncAPI = HuskSyncAPI.getInstance();
        this.usePokeSyncMixins = PokeSyncReforged.getInstance().isUsePokeSyncMixins();
        register();
    }

    private void register() {
        HuskSync huskSync = huskSyncAPI.getPlugin();
        for (PixelmonDataType type : PixelmonDataType.values()) {
            if (Config.isEnable(type)) {
                huskSyncAPI.registerDataSerializer(type.getIdentifier(), type.createSerializer(huskSync));
            }
        }
        Bukkit.getPluginManager().registerEvents(this, PokeSyncReforged.getInstance());
    }
    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
    public void onBukkitDataSave(BukkitDataSaveEvent event) {
        event.editData(unpacked -> {
            UUID uuid = event.getUser().getUuid();
            PCStorage pc = StorageProxy.getPCForPlayerNow(uuid);
            PlayerPartyStorage party = StorageProxy.getPartyNow(uuid);
            for (PixelmonDataType type : PixelmonDataType.values()) {
                if (Config.isEnable(type)) {
                    if (type == PixelmonDataType.PC) {
                        unpacked.setData(type.getIdentifier(), type.createData(pc));
                    } else {
                        unpacked.setData(type.getIdentifier(), type.createData(party));
                    }
                    LogUtils.debug(String.format("Data saved for %s for %s", event.getUser().getUsername(), type.getIdentifier()));
                }
            }
            LogUtils.debug(String.format("PokeSyncReforged saved for data [%s]", unpacked.getId()));
        });
    }

    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
    public void onBukkitPreSync(BukkitPreSyncEvent event) {
        if (usePokeSyncMixins) {
            PokeSyncMixinsHook.callPreEvent(event.getUser().getUuid());
        }
    }

    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
    public void onBukkitSyncComplete(BukkitSyncCompleteEvent event) {
        UUID uuid = event.getUser().getUuid();
        PlayerPartyStorage party = StorageProxy.getPartyNow(uuid);
        PCStorage pc = StorageProxy.getPCForPlayerNow(uuid);
        HolderLookup.Provider registryAccess = ServerLifecycleHooks.getCurrentServer().registryAccess();
        if (party != null) {
            StorageProxy.getSaveAdapter().save(party, registryAccess);
            party.setHasChanged(false);
            LogUtils.debug(String.format("Load Party saved for %s | %d pokemon", event.getUser().getUsername(), party.countAll()));
        }

        if (pc != null) {
            StorageProxy.getSaveAdapter().save(pc, registryAccess);
            pc.setHasChanged(false);

            // 失效并重取
            StorageProxy.getStorageManager().invalidateCache(pc);
            pc = StorageProxy.getPCForPlayerNow(uuid);

            // 如果玩家在线，主动下发初始化包，立刻刷新客户端视图
            ServerPlayer player = PixelUtils.getPlayer(uuid);
            if (pc != null && player != null) {
                LogUtils.debug("ReLoad Pc Data NOW");
                pc.initialize(player);
            }

            LogUtils.debug(String.format("Load PC saved for %s | %d pokemon", event.getUser().getUsername(), pc.countAll()));;
        }
        StorageProxy.getStorageManager().invalidateCache(pc);
        if (usePokeSyncMixins) {
            System.out.println("UsePokeSyncMixins Call");
            PokeSyncMixinsHook.callCompleteEvent(uuid);
        }
    }

}
